package com.songyang.yougnsql.core.transaction;

import com.songyang.yougnsql.common.ErrorMsg;
import com.songyang.yougnsql.common.ExceptionHandler;
import com.songyang.yougnsql.common.YoungSQLException;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * 该接口通过维护文件记录事务状态。
 * 规定：
 * 1、一个事务状态占用1个字节
 * 2、事务的状态按照事务id的顺序在文件中排列
 * 3、文件前8个字节作为文件头，存储该文件记录事务状态的数量。
 * 4、事务id为0则定义为超级事务，状态永远是committed
 * 举例：
 * 事务id数量   id为0的状态  id为1的状态
 * [8字节]      [1字节]     [1字节]
 *
 * @author yanceysong
 */
public interface TransactionManager extends AutoCloseable {
    /**
     * 超级事务，永远为committed状态
     */
    long SUPER_XID = 0;

    /**
     * 创建一个事务文件，返回一个事务管理
     *
     * @param path 事务文件的路径
     * @return 事务管理
     */
    private static Boolean create(String path) {
        File f = new File(path +File.separator+"YoungSQL"+ TransactionManagerImpl.XID_SUFFIX);
        try {
            if (!f.createNewFile()) {
                throw new YoungSQLException(ErrorMsg.FILE_EXISTS_EXCEPTION);
            }
            RandomAccessFile randomAccessFile = new RandomAccessFile(f, "rw");
            FileChannel fileChannel = randomAccessFile.getChannel();
            // 写空XID文件头
            ByteBuffer buf = ByteBuffer.wrap(new byte[TransactionManagerImpl.LEN_XID_HEADER_LENGTH]);
            fileChannel.position(0);
            fileChannel.write(buf);
            fileChannel.close();
            randomAccessFile.close();
            return true;
        } catch (Exception e) {
            ExceptionHandler.handler(e);
        }
        return false;
    }

    /**
     * 创建默认的事务管理，文件默认为当前路径的Young.xid
     *
     * @return 事务管理
     */
    static TransactionManagerImpl open() throws YoungSQLException {
        return TransactionManager.open("Young");
    }


    /**
     * 根据已有的事务文件返回一个事务管理
     *
     * @param path 事务文件的路径
     * @return 事务管理
     */
    static TransactionManagerImpl open(String path) throws YoungSQLException {
        File f = new File(path + File.separator + "YoungSQL" + TransactionManagerImpl.XID_SUFFIX);
        try {
            //如果不存在就去创建，创建失败就抛异常
            if (!f.exists() && !create(path)) {
                throw new YoungSQLException(ErrorMsg.FILE_CREATE_FAILED_EXCEPTION);
            }
            if (!f.canRead() || !f.canWrite()) {
                throw new YoungSQLException(ErrorMsg.FILE_CANNOT_RW_EXCEPTION);
            }
            RandomAccessFile randomAccessFile = new RandomAccessFile(f, "rw");
            FileChannel fileChannel = randomAccessFile.getChannel();
            return new TransactionManagerImpl(randomAccessFile, fileChannel);
        } catch (YoungSQLException | IOException e) {
            ExceptionHandler.handler(e);
        }
        throw new YoungSQLException(ErrorMsg.CREATE_TM_FAILED);
    }

    /**
     * 开始一个事务
     *
     * @return 事务的id
     */
    long begin();

    /**
     * 提交一个事务
     *
     * @param xid 事务的id
     */
    void commit(long xid);

    /**
     * 删除一个事务
     *
     * @param xid 事务的id
     */
    void abort(long xid);

    /**
     * 事务是否处于Active状态
     *
     * @param xid 事务的id
     * @return 结果
     */
    boolean isActive(long xid);

    /**
     * 查看事务是否已经提交
     *
     * @param xid 事务id
     * @return 是否已经提交
     */
    boolean isCommitted(long xid);

    /**
     * 查看事务是否已经被去除
     *
     * @param xid 事务id
     * @return 结果
     */
    boolean isAborted(long xid);

    /**
     * 关闭资源
     */
    void close();

}
